<?php
/*
 * @Descripttion: 
 * @version: 1.0
 * @Author: Sam
 * date: 2021-12-02 11:02:17
 * @LastEditors: Sam
 * @LastEditTime: 2022-03-10 15:55:27
 */
namespace app\api\controller;
use app\__MODULE__\model\{Seckill as SeckillModel,SeckillDetail,User};
use think\facade\Db;
use hg\apidoc\annotation as Apidoc;

/**
 * @Apidoc\Title("秒杀模块")
 */
class Seckill extends Base {

       /**
     * @Apidoc\Title("活动列表")
     * @Apidoc\Url("/api/get_seckill_list")
     * @Apidoc\Method("GET")
     * @Apidoc\Returned ("[]",type="object",desc="活动列表",
     *          @Apidoc\Returned ("id",type="int",desc="活动id"),
     *          @Apidoc\Returned ("title",type="string",desc="标题"),
     *          @Apidoc\Returned ("sub_title",type="string",desc="小标题"),
     *          @Apidoc\Returned ("start_time",type="string",desc="开始时间"),
     *          @Apidoc\Returned ("end_time",type="string",desc="结束时间"),
     *          @Apidoc\Returned ("goods_thumb",type="string",desc="活动图片"),
     *          @Apidoc\Returned ("goods_price",type="string",desc="价格"),
     *          @Apidoc\Returned ("stock",type="string",desc="库存"),
     *          @Apidoc\Returned ("is_join",type="int",desc="是否已参与false 未参与 true 已参与"),
     *     )
     */
    public function list(){
        $uid = self::get_user_id();
        $list = SeckillModel::where('is_show',1)->field('id,title,sub_title,start_time,end_time,goods_thumb,goods_price,price,stock')->order('start_time desc')->select();
        foreach ($list as $key => &$value) {
            if(time() < $value->start_time){
                $status = 0;
            }elseif(time() > $value->end_time){
                $status = 2;
            }else{
                $status = 1;
            }
            $value['start_time']  = date('Y-m-d H:i',$value['start_time']);
            $value['end_time']    = date('Y-m-d H:i',$value['end_time']);
            $value['status_text'] = $status;
            $value['is_join']     = SeckillDetail::where(['uid'=>$uid,'aid'=>$value['id']])->count() ? true : false;
        }
        \json_response(1,'success',$list);
    }

        /**
     * @Apidoc\Title("活动详情")
     * @Apidoc\Url("/api/get_seckill_detail")
     * @Apidoc\Method("GET")
     * @Apidoc\Param ("id",type="int",desc="活动id",require=true),
     * @Apidoc\Returned ("detail",type="object",desc="活动详情",
     *          @Apidoc\Returned ("id",type="int",desc="活动id"),
     *          @Apidoc\Returned ("title",type="string",desc="标题"),
     *          @Apidoc\Returned ("sub_title",type="string",desc="小标题"),
     *          @Apidoc\Returned ("start_time",type="string",desc="开始时间"),
     *          @Apidoc\Returned ("end_time",type="string",desc="结束时间"),
     *          @Apidoc\Returned ("goods_thumb",type="string",desc="活动图片"),
     *          @Apidoc\Returned ("goods_price",type="string",desc="价格"),
     *          @Apidoc\Returned ("stock",type="string",desc="库存"),
     *          @Apidoc\Returned ("is_join",type="int",desc="是否已参与false 未参与 true 已参与"),
     *        @Apidoc\Returned ("seckill",type="object",desc="我的秒杀",
     *          @Apidoc\Returned ("order_sn",type="string",desc="订单编号"),
     *          @Apidoc\Returned ("price",type="string",desc="当前价格"),
     *          @Apidoc\Returned ("source_price",type="string",desc="原价"),
     *          @Apidoc\Returned ("pay_status",type="int",desc="支付状态 0 未支付 1已支付"),
     *     )
     *     )
     */
    public function detail(){
        $aid     = \param_check('id');
        $uid     = self::get_user_id();
        $data    = [];
        if(!$data['detail'] = SeckillModel::where(['id'=>$aid,'is_show'=>1])->field('id,title,sub_title,start_time,end_time,goods_thumb,goods_price,stock')->find()) \json_response(0,'未找到秒杀活动或已下架');
        $data['detail']['status_text'] = 0; //进行中
        if($data['detail']->start_time > time()){
            $data['detail']['status_text'] = -1; //未开始 
        }elseif($data['detail']->end_time <= time()){
            $data['detail']['status_text'] = 1; //已结束 
        }
        $data['detail']['start_time']  = date('Y-m-d H:i', $data['detail']['start_time']);
        $data['detail']['end_time']    = date('Y-m-d H:i', $data['detail']['end_time']);
        $data['detail']['seckill']     = SeckillDetail::where(['uid'=>$uid,'aid'=> $data['detail']['id']])->find();
        $data['detail']['is_join']     = count($data['detail']['seckill'] ) ? true : false;
        json_response(1,'success',$data);
    }

    /**
     * @Apidoc\Title("发起秒杀")
     * @Apidoc\Url("/api/start_seckill")
     * @Apidoc\Method("POST")
     * @Apidoc\Param ("aid",type="int",desc="活动id",require=true),
     */
    public function start_seckill(){
        $uid      = self::get_user_id();
        redis_lock("{$this->redis_key}:start_bargain:{$uid}",$uid,function($uid, $redis){
            $user     = User::get($uid);
            $aid = \param_check('aid');
            if($seckill_detail = SeckillDetail::where(['uid'=>$uid,'aid'=>$aid])->find()) return error('已经参与过秒杀了');
            $seckill = SeckillModel::get($aid);
            if(!$seckill) return error('活动不存在');
            if(!$seckill->is_show) return error('活动已下线');
            if( !$redis->lLen("{$this->redis_key}:SeckillStock:{$aid}")) return error('已经被抢光了');
            if($seckill->end_time < time()) return error('活动已结束');
            if($seckill->start_time > time()) return error('活动未开始');
            $res = $redis->rPop("{$this->redis_key}:SeckillStock:{$aid}");
            if(!$res) return error('当前访问人数过多, 请稍后再试~');
            Db::startTrans();
            try {
                SeckillDetail::create([
                    'uid' => $uid,
                    'aid' => $seckill->id,
                    'order_sn' => SeckillDetail::create_order_no('MS'),
                    'goods_id' => $seckill->goods_id,
                    'price' => $seckill->price,
                    'source_price' => $seckill->goods_price,
                ]);
                Db::commit();
            } catch (\Exception $e) {
                Db::rollback();
                return error($e->getMessage());
            }
            return success('success');
        });  
    }


        /**
     * 定时任务 未支付订单秒杀库存回滚
     * @return void
     * @author Sam
     * date 2021-12-06
     */
    public function rollback_seckill(){
        $redis = redis_instance();
        $list = SeckillDetail::where('pay_status',0)->field('id,aid,create_time')->select();
        foreach ($list as $key => $value) {
            if(  (time() - strtotime($value->create_time)) > 5 * 60){ //5分钟过期  
               $res =  $redis->lPush("{$this->redis_key}:SeckillStock:{$value->aid}", 1); //重新放入redis库存
                if($res){
                    $value->pay_status = -1;
                    $value->save();
                }
                
            }
        }
    }
        /**
     * @Apidoc\Title("秒杀订单支付")
     * @Apidoc\Url("/api/seckill_pay")
     * @Apidoc\Method("post")
     * @Apidoc\Param ("order_sn",type="string",desc="订单编号",require=true),
     * @Apidoc\Returned ("js_config",type="object",desc="支付参数",
     *          @Apidoc\Returned ("timeStamp",type="string",desc="时间戳"),
     *          @Apidoc\Returned ("nonceStr",type="string",desc="随机字符串"),
     *          @Apidoc\Returned ("signType",type="string",desc="加密方式"),
     *          @Apidoc\Returned ("paySign",type="string",desc="签名")
     *     )
     */
    public  function  seckill_pay(){
        $uid = self::get_user_id();
        $order_sn = \param_check('order_sn');
        $order    = SeckillDetail::where(['order_sn'=>$order_sn,'uid'=>$uid])->find();
        !$order   && \json_response(0,'订单不存在');
        $order->status !=1 && json_response(0,'订单不需支付');
        $order->pay_status ==1 && json_response(0,'订单已支付');
        $order->status !=1 && json_response(0,'订单不需支付');
        $wechat_server = new \app\common\api\WeChat();
        $jsConfig = $wechat_server->pay_param(User::where('id',$uid)->value('openid'),$order->order_sn,$order->price, str_replace(request()->pathinfo(),'api/bargain/notify',request()->url(true)));
        $info['js_config'] = $jsConfig;
        json_response(1,'success',$info);
    }



    /**
     * 支付回调
     * @return [type] [description]
     */
    public function notify(){
        $wechat_server = new \app\common\api\WeChat();
        $wechat_server->check_sign(function($data){
             Db::startTrans();
             try{
                  $order = SeckillDetail::where('order_sn',$data['out_trade_no'])->find();
                  if($order && !$order->pay_status){
                     $order->pay_status         = 1;
                     $order->pay_time       = time();
                     $order->transaction_id = $data['transaction_id'];
                     $order->total_fee      = $data['total_fee'];
                     $order->save();
                     $order->activity->stock -= 1;
                     $order->activity->save();
                 }
                 Db::commit();
             }catch(\Excepion $e){
                 Db::rollback();
             }
            
        });
     }
    function randomFloat($min = 0, $max = 1) {
        return round($min + mt_rand() / mt_getrandmax() * ($max - $min),2);
    }
    
}
